package mr.aurelien.blackboard.view;

import java.util.ArrayList;
import mr.aurelien.blackboard.model.Blackboard;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Pair;
import android.view.MotionEvent;
import android.view.View;

public class BlackboardUI extends View {
	private Paint paint = new Paint();
	private Path path = new Path();
	ArrayList<Pair<Path, Paint>> paths = new ArrayList<Pair<Path, Paint>>();
	private Blackboard board = new Blackboard();
	private boolean readOnly = false;
	private boolean redrawNeeded = false;
	private int height = 0;
	private int width = 0;
	public int penColor = Color.BLACK;
	public int penSize = 1;

	public void redrawNeeded() {
		redrawNeeded = true;
		invalidate();
	}

	public void init(Context context) {
		if (context!=null)
		{
			this.width = context.getResources().getDisplayMetrics().widthPixels;
			this.height = context.getResources().getDisplayMetrics().heightPixels;
		}
	    paint.setAntiAlias(true);
		paint.setStyle(Paint.Style.STROKE);
		paint.setStrokeJoin(Paint.Join.ROUND);
		paint.setStrokeWidth(penSize);
		paint.setColor(penColor);
		paint.setTextSize(20f); //used when debug
	    
	    //Log.i("BlackboardUI", "Context size: " + this.width +"x"+ this.height );
	}
	
	public BlackboardUI(Context context)
	{
	    super(context);
	    init(context);
	}

	public BlackboardUI(Context context, AttributeSet attrs)
	{
	    super(context, attrs);
	    init(context);
	} 

//	@Override
	protected void onMeasure (int widthMeasureSpec, int heightMeasureSpec){
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		
		this.height=View.MeasureSpec.getSize(heightMeasureSpec);
		this.width=View.MeasureSpec.getSize(widthMeasureSpec);
		
		Log.i("BlackboardUI", "Measure changed: " + this.width +"x"+ this.height );
	}
	
	@SuppressLint("DrawAllocation") @Override
	protected void onDraw(Canvas canvas) {

		if (redrawNeeded)
		{
			load(board);	
			redrawNeeded = false;
		}

		for (Pair<Path, Paint> p : paths) {
			canvas.drawPath(p.first, p.second);
		}
		
		if(!path.isEmpty())
			canvas.drawPath(path, paint);
		
		// For debug information
//		int size = board.getStrokeSize();
//		 for(int i=0; i<size;i++)
//		 {
//		 canvas.drawText("Stoke"+i+"="+board.getStroke(i).getPointSize(),10,30+(i*20),
//		 new Paint());
//		 }
	}
	
	

	/*
	 * load from another existing Blackboard object
	 */
	public void load(Blackboard savedBoard) {
		
		if (savedBoard.isEmpty())
		{
			Log.i("BlackboardUI","Board nothing to load");
			return;
		}
		this.board=savedBoard;
		paths.clear();
		int size = savedBoard.getStrokeSize();
		// Parse each stroke
		for (int i = 0; i < size; i++) {
			if (savedBoard.getStroke(i).isEmpty())
				break;
			
			path.moveTo(savedBoard.getStroke(i).getPoint(0).getX(), savedBoard
					.getStroke(i).getPoint(0).getY());

			// Parse stroke's points
			for (int j = 1; j < savedBoard.getStroke(i).getPointSize(); j++) {
				path.lineTo(savedBoard.getStroke(i).getPoint(j).getX(),
							savedBoard.getStroke(i).getPoint(j).getY());
			}
			paths.add(new Pair<Path, Paint>(path, paint));
			path.reset();
		}
		invalidate();
		Log.i("BlackboardUI","Board loaded");
		Log.i("BlackboardUI","Pair recreated: "+paths.size());
	}

	/*
	 * load from JSON saved Blackboard object
	 */
	public void load(String JSON) {
		this.board = Blackboard.load(JSON);
		invalidate();
	}
	/*
	 * Save this Blackboard object to JSON 
	 */
	public String save() {
		return this.board.toGSON();
	}
	
	@Override
	public boolean onTouchEvent(MotionEvent event) {
		if (readOnly)
			return false;
		float eventX = event.getX();
		float eventY = event.getY();
		long delay = event.getEventTime();
		
		switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				board.newStroke();
				board.addPoint(eventX, eventY, delay);
				board.setPenColor(penColor);
				board.setPenSize(penSize);
				paint = new Paint();
				path = new Path();
				int historySize = event.getHistorySize();
				for (int i = 0; i > historySize; i++) {
					board.addPoint(event.getHistoricalX(i),
							event.getHistoricalX(i),
							event.getHistoricalEventTime(i));
				}
				init(null); // set paint object
				path.moveTo(eventX, eventY);
	
				return true;
			case MotionEvent.ACTION_MOVE:
				board.addPoint(eventX, eventY, delay);
				path.lineTo(eventX, eventY);
				break;
			case MotionEvent.ACTION_UP:
				board.addPoint(eventX, eventY, delay);
				path.lineTo(eventX, eventY);
				// End of stroke, add this to 
				paths.add(new Pair<Path, Paint>(path, paint));
				break;
			default:
				return false;
		}
		// Schedules a repaint.
		invalidate();
		return true;
	}
	
	/*
	 * Clean everything displayed on board.
	 */
	public void clean()
	{
		this.board.wipe();
		this.paths.clear();
		this.path.reset();
		invalidate();
	}
}
